/**
 *
 */
package org.shortestpath.service;

import org.shortestpath.core.Point;
import org.shortestpath.service.dao.DbDao;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Collections;
import java.util.Comparator;
import java.util.Vector;

import org.postgis.Geometry;
import org.postgis.LineString;
import org.postgis.MultiLineString;
import org.postgis.PGgeometry;
import org.shortestpath.core.exception.InvalidPathException;
import org.shortestpath.core.util.DijkrastUtil;

/**
 * @author Thilani
 *
 */
public class DbService {

    private DbDao dbDao;

    /**
     *
     * @return
     * @throws SQLException
     */
    public Vector<PGgeometry> getAllRoadGeom() throws SQLException {
        Vector<PGgeometry> geometryVector = new Vector<PGgeometry>();

        dbDao = new DbDao();
        ResultSet resultSet = dbDao.getAllRoads();
        while (resultSet.next()) {
            /*
             * Retrieve the geometry as an object then cast it to the
             * geometry type. Print things out.
             */
            PGgeometry geom = (PGgeometry) resultSet.getObject(1);
            geometryVector.addElement(geom);
        }
        resultSet.close();

        return geometryVector;
    }

    /**
     * 
     * @return
     * @throws java.sql.SQLException
     */
    public Vector<Point> getAllPoints() throws SQLException {
        Vector<Point> pointVector = new Vector<Point>();

        dbDao = new DbDao();
        ResultSet resultSet = dbDao.getAllPoints();
        while (resultSet.next()) {
            /*
             * Retrieve the geometry as an object then cast it to the
             * geometry type. Print things out.
             */
            Double x = (Double) resultSet.getObject(1);
            Double y = (Double) resultSet.getObject(2);
            String adj_nodes = (String) resultSet.getObject(5);
            Point point = new Point(x, y);
            point.setAdj_Nodes(adj_nodes);

            pointVector.addElement(point);
        }
        resultSet.close();

        return pointVector;
    }

    /**
     *
     * @param vertexe
     * @throws SQLException
     */
    public String generateDynamicTable(Vector<Point> vertexes) throws SQLException {
        int pathSize = vertexes.size();
        Point[] pointArray = new Point[pathSize];
        for (int i = 0; i < vertexes.size(); i++) {
            pointArray[i] = vertexes.get(i);
        }
        LineString lineString = new LineString(pointArray);
        LineString[] lines = {lineString};
        MultiLineString multiLineString = new MultiLineString(lines);
        multiLineString.setSrid(-1);
        return dbDao.generateDynamicTable((Geometry) multiLineString, 0);

    }

    /**
     * 
     * @param sql
     * @param userPoint
     * @return
     * @throws java.sql.SQLException
     */
    public Point processNearestRoad(Point userPoint) throws SQLException, InvalidPathException {
        dbDao = new DbDao();
        Vector<Point> pointVector = new Vector<Point>();

        int radius = 100;
        int roadId = -1;
        boolean found = false;       
        
        /*
         * Check the nearest point for the user given point from roads table
         */
        while (!found) {
            String sql = "select road_id from "+ DbDao.ROADS_TABLE_NAME +" where expand(makepoint(" + userPoint.getX() + ", " + userPoint.getY() + "), " + radius
             + ") && the_geom order by distance(makepoint(" + userPoint.getX() + ", " + userPoint.getY() + "),the_geom)";
            ResultSet resultSet = dbDao.executeOnDb(sql);            
            while (resultSet.next()) {
                roadId = Integer.parseInt(resultSet.getObject(1).toString());
                found = true;
                break;
            }
            resultSet.close();
            radius = radius * 2;
        }
        if (roadId == -1) {
            throw new InvalidPathException("The given point not belonges to any roads, please select another point");
        }

        // get the nearest road points from simpleroads and iterates and get the nearest point
        String simpleTableSql = "select x_cor as x, y_cor as y, gid, road_id, adj_nodes from "
                + DbDao.SIMPLE_TABLE_NAME + " WHERE road_id=" + roadId;
        ResultSet simpleTableResultSet = dbDao.executeOnDb(simpleTableSql);
        while (simpleTableResultSet.next()) {
            Double x = (Double) simpleTableResultSet.getObject(1);
            Double y = (Double) simpleTableResultSet.getObject(2);
            roadId = Integer.parseInt(simpleTableResultSet.getObject(4).toString());
            String adj_nodes = (String) simpleTableResultSet.getObject(5);
            Point point = new Point(x, y);

            point.setAdj_Nodes(adj_nodes);
            point.setRoadId(roadId);
            double distance = DijkrastUtil.calculateDistance(userPoint, point);
            point.setDistance(distance);
            pointVector.addElement(point);            
        }
        simpleTableResultSet.close();

        Collections.sort(pointVector, new Comparer());
        return pointVector.elementAt(0);
    }
}

/**
 * The comparer class for sort vector against the distance
 *
 * @author Thilani
 *
 */
class Comparer implements Comparator {
    public int compare(Object obj1, Object obj2)
    {
    	double i1 = ((Point)obj1).getDistance();
    	double i2 = ((Point)obj2).getDistance();
    	return (int) ((Math.abs(i1) - Math.abs(i2))*1000);
    }
}
